# -*- coding: utf-8 -*-
import json
import os
import subprocess
import requests


from typing import Optional, NoReturn,List

from hashlib import sha256

from sqlalchemy.ext.asyncio import AsyncSession

from email_validator import validate_email, EmailNotValidError
from fast_captcha import text_captcha
from fastapi import Request, HTTPException, Response, UploadFile,status
from fastapi.security import OAuth2PasswordRequestForm
from fastapi_pagination.ext.async_sqlalchemy import paginate

from loguru import logger

from app.api import jwt
from app.common.exception import errors
from app.common.log import log
# from backend.app.common.redis import redis_client
from app.common.response.response_code import CodeEnum
from app.core.conf import ST
from app.core.path_conf import AvatarPath
from app.crud import crud_user
from app.database.db_sqlite import async_db_session
from app.models import User
from app.schemas.user import CreateUser, ResetPassword, UpdateUser, ELCode, Auth2
from app.utils import re_verify
from app.utils.format_string import cut_path
from app.utils.generate_string import get_current_timestamp, get_uuid
from app.utils.send_email import send_verification_code_email, SEND_EMAIL_LOGIN_TEXT

from app.core.conf import ST

def check_user_login(username:str,password:str):
    data = {
        "corp_id":ST.LOGIN_CORP_ID,"api_key":ST.LOGIN_API_KEY,"account":username,"password":password
    }
    res = requests.post(url=ST.LOGIN_URL,data=json.dumps(data))
    return res.json()



def python_call_powershell(loginid:str):
    try:
        args=[r"powershell",ST.shell_getuserinfo_path,loginid] #args参数里的ip是对应调用powershell里的动态参数args[0],类似python中的sys.argv[1]
        logger.debug(ST.shell_getuserinfo_path)
        p=subprocess.Popen(args, stdout=subprocess.PIPE)
        dt=p.stdout.read()
        return eval(str(dt, encoding = "utf-8"))
    except Exception as e:
        print (e)
        return False



# 登录的逻辑,就是很简单
async def login(form_data: OAuth2PasswordRequestForm):

    # res = check_user_login(form_data.username,form_data.password)
    # if not res.get('success'):
    #     raise errors.AuthorizationError(msg='密码错误')

    async with async_db_session() as db:
        user_name = form_data.username.lower()
        logger.debug(user_name);
        current_user = await crud_user.get_user_by_loginid(db, user_name)

        # 如果在本地数据库,没有该用户的数据,就去请求该用户的数据,存到本地数据库里
        # if current_user is None:
        #     res = python_call_powershell(user_name)
        #     user_info = res.get('resData')[0]
        #     await crud_user.create_user(db,CreateUser(**user_info))

        # 更新登陆时间
        await crud_user.update_user_login_time(db, user_name)
        # 创建Token
        access_token = jwt.create_access_token(user_name)
        return access_token 
        

# ============================================================================================================================

async def get_users(current_user:User)->List[User]:
    async with async_db_session.begin() as db:
        res = await crud_user.get_users(db)
        return res

        
 

# async def login(obj: Auth):
#     async with async_db_session() as db:
#         current_user = await crud_user.get_user_by_username(db, obj.username)
#         if not current_user:
#             raise errors.NotFoundError(msg='用户名不存在')
#         elif not jwt.verity_password(obj.password, current_user.password):
#             raise errors.AuthorizationError(msg='密码错误')
#         elif not current_user.is_active:
#             raise errors.AuthorizationError(msg='该用户已被锁定，无法登录')
#         # 更新登陆时间
#         await crud_user.update_user_login_time(db, obj.username)
#         # 创建token
#         access_token = jwt.create_access_token(current_user.id)
#         return access_token, current_user.is_superuser


# async def login_email(*, request: Request, obj: Auth2):
#     pass
#     async with async_db_session() as db:
#         current_email = await crud_user.check_email(db, obj.email)
#         if not current_email:
#             raise errors.NotFoundError(msg='邮箱不存在')
#         username = await crud_user.get_username_by_email(db, obj.email)
#         current_user = await crud_user.get_user_by_username(db, username)
#         if not current_user.is_active:
#             raise errors.AuthorizationError(msg='该用户已被锁定，无法登录')
#         try:
#             uid = request.app.state.email_login_code
#         except Exception:
#             raise errors.ForbiddenError(msg='请先获取邮箱验证码再登陆')
        # r_code = await redis_client.get(f'{uid}')
        # if not r_code:
            # raise errors.NotFoundError(msg='验证码失效，请重新获取')
        # if r_code != obj.code:
            # raise errors.CodeError(error=CodeEnum.CAPTCHA_ERROR)
        # await crud_user.update_user_login_time(db, username)
        # access_token = jwt.create_access_token(current_user.id)
        # return access_token, current_user.is_superuser


# async def send_login_email_captcha(request: Request, obj: ELCode):
#     async with async_db_session() as db:
#         if not await crud_user.check_email(db, obj.email):
#             raise errors.NotFoundError(msg='邮箱不存在')
#         username = await crud_user.get_username_by_email(db, obj.email)
#         current_user = await crud_user.get_user_by_loginid(db, username)
#         if not current_user.is_active:
#             raise errors.ForbiddenError(msg='该用户已被锁定，无法登录，发送验证码失败')
#         try:
#             code = text_captcha()
#             await send_verification_code_email(obj.email, code, SEND_EMAIL_LOGIN_TEXT)
#         except Exception as e:
#             log.error('验证码发送失败 {}', e)
#             raise errors.ServerError(msg=f'验证码发送失败: {e}')
#         else:
#             uid = get_uuid()
#             # await redis_client.set(uid, code, settings.EMAIL_LOGIN_CODE_MAX_AGE)
#             request.app.state.email_login_code = uid


# async def register(obj: CreateUser):
#     async with async_db_session.begin() as db:
#         username = await crud_user.get_user_by_loginid(db, obj.alias)
#         if username:
#             raise errors.ForbiddenError(msg='该用户名已注册')
#         email = await crud_user.check_email(db, obj.email)
#         if email:
#             raise errors.ForbiddenError(msg='该邮箱已注册')
#         try:
#             validate_email(obj.email, check_deliverability=False).email
#         except EmailNotValidError:
#             raise errors.ForbiddenError(msg='邮箱格式错误')
#         await crud_user.create_user(db, obj)


# async def get_pwd_rest_captcha(*, username_or_email: str, response: Response):
#     async with async_db_session() as db:
#         code = text_captcha()
#         if await crud_user.get_user_by_loginid(db, username_or_email):
#             try:
#                 response.delete_cookie(key='fastapi_reset_pwd_code')
#                 response.delete_cookie(key='fastapi_reset_pwd_username')
#                 response.set_cookie(
#                     key='fastapi_reset_pwd_code',
#                     value=sha256(code.encode('utf-8')).hexdigest(),
#                     max_age=ST.COOKIES_MAX_AGE
#                 )
#                 response.set_cookie(
#                     key='fastapi_reset_pwd_username',
#                     value=username_or_email,
#                     max_age=ST.COOKIES_MAX_AGE
#                 )
#             except Exception as e:
#                 log.exception('无法发送验证码 {}', e)
#                 raise e
#             current_user_email = await crud_user.get_email_by_username(db, username_or_email)
#             await send_verification_code_email(current_user_email, code)
#         else:
#             try:
#                 validate_email(username_or_email, check_deliverability=False)
#             except EmailNotValidError:
#                 raise HTTPException(status_code=404, detail='用户名不存在')
#             email_result = await crud_user.check_email(db, username_or_email)
#             if not email_result:
#                 raise HTTPException(status_code=404, detail='邮箱不存在')
#             try:
#                 response.delete_cookie(key='fastapi_reset_pwd_code')
#                 response.delete_cookie(key='fastapi_reset_pwd_username')
#                 response.set_cookie(
#                     key='fastapi_reset_pwd_code',
#                     value=sha256(code.encode('utf-8')).hexdigest(),
#                     max_age=ST.COOKIES_MAX_AGE
#                 )
#                 username = await crud_user.get_username_by_email(db, username_or_email)
#                 response.set_cookie(
#                     key='fastapi_reset_pwd_username',
#                     value=username,
#                     max_age=ST.COOKIES_MAX_AGE
#                 )
#             except Exception as e:
#                 log.exception('无法发送验证码 {}', e)
#                 raise e
#             await send_verification_code_email(username_or_email, code)


# async def pwd_reset(*, obj: ResetPassword, request: Request, response: Response):
#     async with async_db_session.begin() as db:
#         pwd1 = obj.password1
#         pwd2 = obj.password2
#         cookie_reset_pwd_code = request.cookies.get('fastapi_reset_pwd_code')
#         cookie_reset_pwd_username = request.cookies.get('fastapi_reset_pwd_username')
#         if pwd1 != pwd2:
#             raise errors.ForbiddenError(msg='两次密码输入不一致')
#         if cookie_reset_pwd_username is None or cookie_reset_pwd_code is None:
#             raise errors.NotFoundError(msg='验证码已失效，请重新获取验证码')
#         if cookie_reset_pwd_code != sha256(obj.code.encode('utf-8')).hexdigest():
#             raise errors.ForbiddenError(msg='验证码错误')
#         await crud_user.reset_password(db, cookie_reset_pwd_username, obj.password2)
#         response.delete_cookie(key='fastapi_reset_pwd_code')
#         response.delete_cookie(key='fastapi_reset_pwd_username')


async def get_user_info(username: str):
    """_summary_

    Args:
        username (str): _根据loginid去本地数据库查询用户信息_

    Raises:
        errors.NotFoundError: _description_

    Returns:
        _type_: _description_
    """
    async with async_db_session() as db:
        user = await crud_user.get_user_by_loginid(db, username)
        if not user:
            res = await crud_user.create_user_from_auo(db,username)
            if res is None:
                raise errors.NotFoundError(msg='该用户不存在')
        return user


# async def update(*, username: str, current_user: User, obj: UpdateUser):
#     async with async_db_session.begin() as db:
#         if not current_user.is_superuser:
#             if not username == current_user.username:
#                 raise errors.AuthorizationError
#         input_user = await crud_user.get_user_by_loginid(db, username)
#         if not input_user:
#             raise errors.NotFoundError(msg='用户不存在')
#         if input_user.username != obj.username:
#             username = await crud_user.get_user_by_loginid(db, obj.username)
#             if username:
#                 raise errors.ForbiddenError(msg='该用户名已存在')
#         if input_user.email != obj.email:
#             _email = await crud_user.check_email(db, obj.email)
#             if _email:
#                 raise errors.ForbiddenError(msg='该邮箱已注册')
#             try:
#                 validate_email(obj.email, check_deliverability=False).email
#             except EmailNotValidError:
#                 raise errors.ForbiddenError(msg='邮箱格式错误')
#         if obj.mobile_number is not None:
#             if not re_verify.is_mobile(obj.mobile_number):
#                 raise errors.ForbiddenError(msg='手机号码输入有误')
#         if obj.wechat is not None:
#             if not re_verify.is_wechat(obj.wechat):
#                 raise errors.ForbiddenError(msg='微信号码输入有误')
#         if obj.qq is not None:
#             if not re_verify.is_qq(obj.qq):
#                 raise errors.ForbiddenError(msg='QQ号码输入有误')
#         count = await crud_user.update_userinfo(db, input_user, obj)
#         return count


# async def update_avatar(*, username: str, current_user: User, avatar: UploadFile):
#     async with async_db_session.begin() as db:
#         if not current_user.is_superuser:
#             if not username == current_user.username:
#                 raise errors.AuthorizationError
#         input_user = await crud_user.get_user_by_loginid(db, username)
#         if not input_user:
#             raise errors.NotFoundError(msg='用户不存在')
#         input_user_avatar = input_user.avatar
#         if avatar is not None:
#             if input_user_avatar is not None:
#                 try:
#                     os.remove(AvatarPath + input_user_avatar)
#                 except Exception as e:
#                     log.error('用户 {} 更新头像时，原头像文件 {} 删除失败\n{}', current_user.username, input_user_avatar,
#                               e)
#             new_file = await avatar.read()
#             if 'image' not in avatar.content_type:
#                 raise errors.ForbiddenError(msg='图片格式错误，请重新选择图片')
#             file_name = str(get_current_timestamp()) + '_' + avatar.filename
#             if not os.path.exists(AvatarPath):
#                 os.makedirs(AvatarPath)
#             with open(AvatarPath + f'{file_name}', 'wb') as f:
#                 f.write(new_file)
#         else:
#             file_name = input_user_avatar
#         count = await crud_user.update_avatar(db, input_user, file_name)
#         return count


# async def delete_avatar(*, username: str, current_user: User):
#     async with async_db_session.begin() as db:
#         if not current_user.is_superuser:
#             if not username == current_user.username:
#                 raise errors.AuthorizationError
#         input_user = await crud_user.get_user_by_loginid(db, username)
#         if not input_user:
#             raise errors.NotFoundError(msg='用户不存在')
#         input_user_avatar = input_user.avatar
#         if input_user_avatar is not None:
#             try:
#                 os.remove(AvatarPath + input_user_avatar)
#             except Exception as e:
#                 log.error('用户 {} 删除头像文件 {} 失败\n{}', input_user.username, input_user_avatar, e)
#         else:
#             raise errors.NotFoundError(msg='用户没有头像文件，请上传头像文件后再执行此操作')
#         count = await crud_user.delete_avatar(db, input_user.id)
#         return count


async def get_user_list():
    async with async_db_session() as db:
        user_select = crud_user.get_users()
        return await paginate(db, user_select)


# async def update_permission(pk: int):
#     async with async_db_session.begin() as db:
#         if await crud_user.get_user_by_id(db, pk):
#             count = await crud_user.super_set(db, pk)
#             return count
#         else:
#             raise errors.NotFoundError(msg='用户不存在')


# async def update_active(pk: int):
#     async with async_db_session.begin() as db:
#         if await crud_user.get_user_by_id(db, pk):
#             count = await crud_user.active_set(db, pk)
#             return count
#         else:
#             raise errors.NotFoundError(msg='用户不存在')


# async def delete(*, username: str, current_user: User):
#     async with async_db_session.begin() as db:
#         if not current_user.is_superuser:
#             if not username == current_user.username:
#                 raise errors.AuthorizationError
#         input_user = await crud_user.get_user_by_loginid(db, username)
#         if not input_user:
#             raise errors.NotFoundError(msg='用户不存在')
#         input_user_avatar = input_user.avatar
#         try:
#             if input_user_avatar is not None:
#                 os.remove(AvatarPath + input_user_avatar)
#         except Exception as e:
#             log.error(f'删除用户 {input_user.username} 头像文件:{input_user_avatar} 失败\n{e}')
#         finally:
#             count = await crud_user.delete_user(db, input_user.id)
#             return count


# async def get_employees_by_loginid(db: AsyncSession,loginid:str)-> List[User]:

#     async def get_employees(db: AsyncSession,loginid:str):
#         employees = await crud_user.get_employees_by_boss_loginid(db,loginid)
#         for employee in employees:
#             all_employees.append(employee)
#             if employee.boss_level < 99:
#                 employees = await get_employees(db,employee.loginid)
            

#     all_employees = []
#     await get_employees(db,loginid)
#     return all_employees

